﻿using AutoMapper;
using B.S.BaseData.Api.Read.Command.RBAC;
using B.S.BaseData.ErrorCode;
using B.S.BaseData.Infrastructure.Interface;
using B.S.BataBase.Domain.DTO;
using B.S.BataBase.Domain.DTO.Token;
using B.S.BataBase.Domain.RBAC;
using MediatR;
using Microsoft.IdentityModel.Tokens;
using Newtonsoft.Json;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;

namespace B.S.BaseData.Api.Read.CommandHandler.RBAC
{
    public class RefreshTokenQueryCommandHandler : IRequestHandler<RefreshTokenQueryCommand, APIResult<TokenResponse>>
    {
        private readonly IBaseRepository<UserModel> _userrepository;
        private readonly IBaseRepository<UserRoleModel> _userroleRepository;
        private readonly IBaseRepository<RoleModel> _roleroleRepository;
        private readonly IMapper _mapper;
        private readonly IHttpContextAccessor _contextAccessor;
        private readonly IConfiguration _config;
        /// <summary>
        /// 日志服务
        /// </summary>
        private readonly ILogger<RefreshTokenQueryCommandHandler> _logger;
        public RefreshTokenQueryCommandHandler(IBaseRepository<UserModel> userrepository,
            IBaseRepository<UserRoleModel> userroleRepository,
            IMapper mapper,
            IBaseRepository<RoleModel> roleroleRepository,
            IConfiguration config,
            IHttpContextAccessor contextAccessor)
        {
            _userrepository = userrepository;
            _userroleRepository = userroleRepository;
            _mapper = mapper;
            _roleroleRepository = roleroleRepository;
            _config = config;
            _contextAccessor = contextAccessor;
        }
        public async Task<APIResult<TokenResponse>> Handle(RefreshTokenQueryCommand request, CancellationToken cancellationToken)
        {
            APIResult<TokenResponse> result = new APIResult<TokenResponse>();
            try
            {
                //判断参数是否为空
                if (string.IsNullOrEmpty(request.AccessToken) || string.IsNullOrEmpty(request.RefreshToken))
                {
                    result.Code = ApiEnum.Fail;
                    result.Msg = "Token为空";
                    return await Task.FromResult(result);
                }

                //// 从过期的access token中获取principal
                var principal = GetPrincipalFromExpiredToken(request.AccessToken);

                if (principal == null)
                {
                    result.Code = ApiEnum.Fail;
                    result.Msg = "无效的Token";
                    return await Task.FromResult(result);
                }

                var userId = Convert.ToInt64(principal.FindFirst("UserId").Value);
                var userName = principal.FindFirst("UserName").Value;

                // 验证refresh token是否有效
                var storedRefreshToken = JsonConvert.DeserializeObject<Refreshtoken>(request.RefreshToken);
                //验证是否有续期token  并且续期token是否过期 
                if (storedRefreshToken == null || storedRefreshToken.Expires < DateTime.Now)
                {
                    result.Code = ApiEnum.Fail;
                    result.Msg = "刷新Token已过期";
                    return await Task.FromResult(result);
                }

                var list = await _userrepository.GetValues(x => x.Id ==userId);
                if (list == null)
                {
                    result.Code = ApiEnum.Fail;
                    result.Msg = $"用户名不存在";
                    return await Task.FromResult(result);
                }
                var data = _userroleRepository.GetAll().Where(x => x.UserId == list.Id).Select(x => x.RoleId).ToList();
                var rolename= await GetRoleName(data);
                result.Code = ApiEnum.Success;
                result.Msg = "Token刷新成功";
                result.Data = CreateTokenString(userId, userName, rolename);
                return await Task.FromResult(result);
            }
            catch (Exception ex)
            {
                result.Code = ApiEnum.Fail;
                result.Msg = "刷新Token失败，服务器异常";
                return await Task.FromResult(result);
            }
            finally
            {
                // 可以在这里添加必要的清理代码
            }
        }

        /// <summary>
        /// 根据角色id集合获取id名称
        /// </summary>
        /// <param name="ids"></param>
        /// <returns></returns>
        public async Task<string> GetRoleName(List<long> ids)
        {
            string s = "";
            foreach (var id in ids)
            {
                s += (await _roleroleRepository.GetValues(x => x.Id == id)).RoleName + ",";
            }
            return s.TrimEnd(',');
        }

        /// <summary>
        /// 生成Token
        /// </summary>
        /// <param name="id"></param>
        /// <param name="loginname"></param>
        /// <param name="rolename"></param>
        /// <returns></returns>
        private TokenResponse CreateTokenString(long id, string loginname, string rolename)
        {
            //配置JWT
            var jwtSettings = _config.GetSection("JwtSettings").Get<JwtSettings>()!;
            //私钥
            var secretByte = Encoding.UTF8.GetBytes(jwtSettings.SigningKey);
            // 非对称加密
            var signingKey = new SymmetricSecurityKey(secretByte);
            // 使用256 生成数字签名
            var signingCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256);

            var claims = new[]
            {
                new Claim("UserId",id.ToString()),
                new Claim("UserName",loginname),
                new Claim("RoleName",rolename)
            };


            // 生成Token
            var token = new JwtSecurityToken(
                issuer: jwtSettings.Issuer,
                audience: jwtSettings.Audience,
                expires: DateTime.Now.AddMinutes(jwtSettings.TokenExpires), // 一天后过期
                signingCredentials: signingCredentials,
                claims: claims
            );
            // 生成token 字符串
            var strToken = new JwtSecurityTokenHandler().WriteToken(token);

            var refreshToken = new Refreshtoken
            {
                Token = Guid.NewGuid().ToString("N"),
                Expires = DateTime.UtcNow.AddDays(jwtSettings.RefreshTokenExpirationDays),
                CreateTime = DateTime.UtcNow,
                UserId = id
            };


            return new TokenResponse
            {
                AccessToken = strToken,
                RefreshToken = JsonConvert.SerializeObject(refreshToken)
            };
        }

        /// <summary>
        ///  解析token
        /// </summary>
        /// <param name="token"></param>
        /// <returns></returns>
        /// <exception cref="SecurityTokenException"></exception>
        public ClaimsPrincipal? GetPrincipalFromExpiredToken(string token)
        {
            //配置JWT
            var jwtSettings = _config.GetSection("JwtSettings").Get<JwtSettings>()!;
            var tokenValidationParameters = new TokenValidationParameters
            {
                ValidateAudience = false,
                ValidateIssuer = false,
                ValidateIssuerSigningKey = true,
                IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSettings.SigningKey)),
                ValidateLifetime = false // 这里我们就是要处理过期的token
            };

            var tokenHandler = new JwtSecurityTokenHandler();
            var principal = tokenHandler.ValidateToken(token, tokenValidationParameters, out var securityToken);

            if (securityToken is not JwtSecurityToken jwtSecurityToken ||
                !jwtSecurityToken.Header.Alg.Equals(SecurityAlgorithms.HmacSha256, StringComparison.InvariantCultureIgnoreCase))
                throw new SecurityTokenException("Invalid token");

            return principal;
        }
    }
}
